package com.wg.net.codec;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.net.NetConfig;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * TCP 消息编码器（基于长度头协议）
 * <p>
 * 编码格式（大端序，网络字节序）：
 * <pre>
 * +----------------+-------------------+
 * |   长度头（4字节） |     数据体（N字节）   |
 * +----------------+-------------------+
 * </pre>
 * - 长度头：4字节无符号整数（int类型），表示数据体的字节长度（不含长度头自身）
 * - 数据体：原始业务数据的字节数组
 *
 * @author 少爷123
 */
public class MyEncoder extends MessageToByteEncoder<byte[]> {
    private static final Log log = LogFactory.get();

    /**
     * 最大允许的数据体长度（防止内存溢出，可根据业务调整）
     */
    private static final int MAX_DATA_LENGTH = NetConfig.getInstance().getMaxFrameLength();

    @Override
    protected void encode(ChannelHandlerContext ctx, byte[] buffer, ByteBuf out) {
        // 1. 输入校验（防止空指针或非法数据）
        if (buffer == null) {
            log.warn("编码失败：输入数据为空，关闭连接");
            ctx.close();
            return;
        }

        // 2. 校验数据体长度（防止超大报文导致内存溢出）
        int dataLength = buffer.length;
        if (dataLength > MAX_DATA_LENGTH) {
            log.error("编码失败：数据体长度非法（当前: {}，最大允许: {}）", dataLength, MAX_DATA_LENGTH);
            ctx.close();
            return;
        }

        try {
            // 3. 写入长度头（网络字节序，大端）
            out.writeInt(dataLength);

            // 4. 写入数据体
            out.writeBytes(buffer);

            // 5. 记录编码结果（调试用）
            if (log.isTraceEnabled()) {
                log.trace("编码完成 | 总长度: {}（长度头4字节+数据体{}字节）",
                        dataLength + 4, dataLength);
            }

        } catch (Exception e) {
            // 6. 异常处理（记录日志并传播异常）
            log.error("编码过程中发生异常 | 数据体长度: {}，异常信息: {}", dataLength, e.getMessage(), e);
            ctx.fireExceptionCaught(e); // 通知上层处理器异常
            throw e; // 终止当前编码流程
        }
    }
}